﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ddbs.QE.Message;
using Ddbs.QE.Parser.Front.Serialization;
using System.Data;
using System.Collections;
using Ddbs.QE.DBMSLibrary;
using QueryHandler;

namespace Ddbs.QE.Client
{
    public class QEProcessor
    {
        /// <summary>
        /// Validate user input command
        /// </summary>
        /// <param name="input"></param>
        /// <param name="info">提示信息，用于在用户输入验证失败时给用户进行提示</param>
        /// <returns></returns>
        public static bool ValidateUserInput(string input, out string info)
        {

            bool validateResult = true;
            info = null;

            //TODO: 
            return validateResult;
        }

        /// <summary>
        /// 如果用户输入的是SQL 语句，该函数解析sql 后，生成一些子查询，组合成QEMessage 后，发送到特定的站点 
        /// </summary>
        /// <param name="command"></param>
        /// <returns></returns>
        public static List<QEMessage> ParseQeury(string command, string sitename, ref string str)
        {
            return QueryProcessor.Handle(command, sitename, ref str);
        }

        // 访问DBMSHandler 的函数
        // 调用返回后，设置tablename
        public static DataSet handleDBMSQuery(string strConnection, string queryCommand)
        {
            return MySQLHandler.QueryRequest(strConnection, queryCommand);
        }

        /// <summary>
        /// 对于具有相同字段的l和r， 合并数据集合
        /// </summary>
        /// <param name="currentDataTable"></param>
        /// <param name="dataTableAdded"></param>
        /// <returns></returns>
        public static DataTable UnionData(DataTable currentDataTable, DataTable dataTableAdded)
        {
            if (currentDataTable == null
                || currentDataTable.Rows.Count == 0
                || dataTableAdded == null
                || dataTableAdded.Rows.Count == 0)
            {
                return null;
            }
            try
            {
                currentDataTable.Merge(dataTableAdded, true, MissingSchemaAction.Add);

            }
            catch (Exception exp)
            {
                return null;
            }
            return currentDataTable;
        }

        public void DisplayProducts(DataTable table)
        {
            var productNames = from products in table.AsEnumerable() select products.Field<string>("ProductName");
            Console.WriteLine("Product Names: ");
            foreach (string productName in productNames)
            {
                Console.WriteLine(productName);
            }
        }

        /// <summary>
        /// 根据 key1 和 key2 作join 操作
        /// 应用场景：
        ///     1. 同一个表的垂直分片
        ///     2. 不同表之间进行Join 
        /// </summary>
        /// <param name="TableLeft">数据表#1</param>
        /// <param name="TableRight">数据表#2</param>
        /// <param name="keyLeft">表#1中键的名称</param>
        /// <param name="keyRight">表#1中键的名称</param>
        /// <param name="columnsLeft">表#1返回那些字段</param>
        /// <param name="columnsRight">表#1返回那些字段</param>
        /// <param name="RecCount">作Join 后记录的数目</param>
        /// <returns></returns>
        public static DataTable JoinData(DataTable TableLeft, DataTable TableRight, string keyLeft, string keyRight, string[] columnsLeft, string[] columnsRight, out int RecCount)
        {
            DataTable dataTable = new DataTable();
            var ret = from p in TableLeft.AsEnumerable()
                      join q in TableRight.AsEnumerable()
                      on p.Field<int>(keyLeft) equals q.Field<int>(keyRight) into UP
                      from q in UP.DefaultIfEmpty()
                      select new
                      {
                          left = p,
                          right = q
                      };
            RecCount = ret.Count();
            int count = ret.Count();
            for (int i = 0; i < count; i++)
            {

                DataRow row = dataTable.NewRow();
                for (int j = 0; j < columnsLeft.Length; j++)
                {
                    string columnName = columnsLeft[j];
                    Object value = ret.ElementAt(i).left.Field<Object>(columnName);

                    if (!dataTable.Columns.Contains(columnName))
                    {
                        dataTable.Columns.Add(columnName, value.GetType());
                    }

                    row[columnName] = value;
                }

                for (int j = 0; j < columnsRight.Length; j++)
                {
                    string columnName = columnsRight[j];
                    Object value = ret.ElementAt(i).right.Field<Object>(columnName);

                    if (!dataTable.Columns.Contains(columnName))
                    {
                        dataTable.Columns.Add(columnName, value.GetType());
                    }

                    row[columnName] = value;

                }
                dataTable.Rows.Add(row);
            }

            return dataTable;

        }

        /// <summary>
        /// 笛卡儿积
        /// </summary>
        /// <param name="TableLeft"></param>
        /// <param name="TableRight"></param>
        /// <param name="columnsLeft"></param>
        /// <param name="columnsRight"></param>
        /// <param name="RecCount"></param>
        /// <returns></returns>
        public static DataTable CartesianProduct(DataTable TableLeft, DataTable TableRight, string[] columnsLeft, string[] columnsRight, out int RecCount)
        {
            DataTable dataTable = new DataTable();

            var ret = from p in TableLeft.AsEnumerable()
                      from q in TableRight.AsEnumerable()
                      select new
                      {
                          left = p,
                          right = q
                      };
            RecCount = ret.Count();
            int count = ret.Count();
            for (int i = 0; i < count; i++)
            {

                DataRow row = dataTable.NewRow();
                for (int j = 0; j < columnsLeft.Length; j++)
                {
                    string columnName = columnsLeft[j];
                    Object value = ret.ElementAt(i).left.Field<Object>(columnName);

                    if (!dataTable.Columns.Contains(columnName))
                    {
                        dataTable.Columns.Add(columnName, value.GetType());
                    }

                    row[columnName] = value;
                }

                for (int j = 0; j < columnsRight.Length; j++)
                {
                    string columnName = columnsRight[j];
                    Object value = ret.ElementAt(i).right.Field<Object>(columnName);

                    if (!dataTable.Columns.Contains(columnName))
                    {
                        dataTable.Columns.Add(columnName, value.GetType());
                    }

                    row[columnName] = value;

                }
                dataTable.Rows.Add(row);
            }

            return dataTable;

        }

        /// <summary>
        /// 从DataSet l 中选择满足 whereCondition 条件的记录
        /// 注意：这里是一个例子
        /// </summary>
        /// <param name="sourceDataTable"></param>
        /// <param name="whereCondition"></param>
        /// <returns></returns>
        public static DataTable SelectDataSample(DataTable sourceDataTable, string whereCondition)
        {
            DataTable dataTable = new DataTable();
            DataRow[] rows = sourceDataTable.Select(whereCondition);

            /*
            ///下面的 id>10 仅是一个例子，请根据实际的情况给定条件
            var ret = from p in sourceDataTable.AsEnumerable()
                      where p.Field<int>("id") > 10    // 在where 部分给定条件
                      select p;
            */
            int count = rows.Count();
            DataColumn[] tableColumns = new DataColumn[sourceDataTable.Columns.Count];
            sourceDataTable.Columns.CopyTo(tableColumns, 0);
            dataTable.Columns.AddRange(tableColumns);
            for (int i = 0; i < count; i++)
            {

                DataRow row = dataTable.NewRow();
                for (int j = 0; j < tableColumns.Length; j++)
                {

                    Object value = rows[i].Field<Object>(tableColumns[j]);
                    row[tableColumns[j]] = value;
                }
                dataTable.Rows.Add(row);
            }

            return dataTable;

        }
        public static DataTable projection(DataTable sourceDataTable, string[] columnNames)
        {

            DataTable dataTable = new DataTable();
            var rows = sourceDataTable.Rows;

            int count = sourceDataTable.Rows.Count;
            List<DataColumn> tableColumns = new List<DataColumn>();
            foreach (string name in columnNames)
            {
                tableColumns.Add(sourceDataTable.Columns[name]);
            }
            dataTable.Columns.AddRange(tableColumns.ToArray());
            for (int i = 0; i < count; i++)
            {
                DataRow row = dataTable.NewRow();
                for (int j = 0; j < tableColumns.Count; j++)
                {

                    Object value = rows[i].Field<Object>(tableColumns[j]);
                    row[tableColumns[j]] = value;
                }
                dataTable.Rows.Add(row);
            }

            return dataTable;
        }
    }




    #region the below are just samples

    public class Samples
    {

        #region join sample
        public static string JoinSample(DataTable Table1, DataTable Table2, string key1, string key2, string[] columnsLeft, string[] columnsRight, out int RecCount)
        {
            StringBuilder buf = new StringBuilder();
            var ret = from p in Table1.AsEnumerable()
                      join q in Table2.AsEnumerable()
                      on p.Field<int>(key1) equals q.Field<int>(key2) into UP
                      from q in UP.DefaultIfEmpty()
                      select new
                      {
                          left = p,
                          right = q
                      };
            RecCount = ret.Count();
            int count = ret.Count();
            for (int i = 0; i < count; i++)
            {
                buf.Append("\r\n");
                for (int j = 0; j < columnsLeft.Length; j++)
                {
                    string columnName = columnsLeft[j];
                    Object value = ret.ElementAt(i).left.Field<Object>(columnName);

                    buf.Append(columnName + "=" + value);
                }

                for (int j = 0; j < columnsRight.Length; j++)
                {
                    string columnName = columnsRight[j];
                    Object value = ret.ElementAt(i).right.Field<Object>(columnName);

                    buf.Append(columnName + "=" + value);
                }
            }

            return buf.ToString();
        }
        #endregion

        #region one example

        public ArrayList DataSetToArrayList(int ColumnIndex, DataTable dataTable)
        {
            ArrayList output = new ArrayList();

            foreach (DataRow row in dataTable.Rows)
                output.Add(row[ColumnIndex]);

            return output;
        }

        public DataTable myJoinMethod(DataTable LeftTable, DataTable RightTable,
            String LeftPrimaryColumn, String RightPrimaryColumn)
        {
            //first create the datatable columns 
            DataSet mydataSet = new DataSet();
            mydataSet.Tables.Add("  ");
            DataTable myDataTable = mydataSet.Tables[0];

            //add left table columns 
            DataColumn[] dcLeftTableColumns = new DataColumn[LeftTable.Columns.Count];
            LeftTable.Columns.CopyTo(dcLeftTableColumns, 0);

            foreach (DataColumn LeftTableColumn in dcLeftTableColumns)
            {
                if (!myDataTable.Columns.Contains(LeftTableColumn.ToString()))
                    myDataTable.Columns.Add(LeftTableColumn.ToString());
            }

            //now add right table columns 
            DataColumn[] dcRightTableColumns = new DataColumn[RightTable.Columns.Count];
            RightTable.Columns.CopyTo(dcRightTableColumns, 0);

            foreach (DataColumn RightTableColumn in dcRightTableColumns)
            {
                if (!myDataTable.Columns.Contains(RightTableColumn.ToString()))
                {
                    if (RightTableColumn.ToString() != RightPrimaryColumn)
                        myDataTable.Columns.Add(RightTableColumn.ToString());
                }
            }

            //add left-table data to mytable 
            foreach (DataRow LeftTableDataRows in LeftTable.Rows)
            {
                myDataTable.ImportRow(LeftTableDataRows);
            }

            ArrayList var = new ArrayList(); //this variable holds the id's which have joined 

            ArrayList LeftTableIDs = new ArrayList();
            LeftTableIDs = this.DataSetToArrayList(0, LeftTable);

            //import righttable which having not equal Id's with lefttable 
            foreach (DataRow rightTableDataRows in RightTable.Rows)
            {
                if (LeftTableIDs.Contains(rightTableDataRows[0]))
                {
                    string wherecondition = "[" + myDataTable.Columns[0].ColumnName + "]='"
                            + rightTableDataRows[0].ToString() + "'";
                    DataRow[] dr = myDataTable.Select(wherecondition);
                    int iIndex = myDataTable.Rows.IndexOf(dr[0]);

                    foreach (DataColumn dc in RightTable.Columns)
                    {
                        if (dc.Ordinal != 0)
                            myDataTable.Rows[iIndex][dc.ColumnName.ToString().Trim()] =
                    rightTableDataRows[dc.ColumnName.ToString().Trim()].ToString();
                    }
                }
                else
                {
                    int count = myDataTable.Rows.Count;
                    DataRow row = myDataTable.NewRow();
                    row[0] = rightTableDataRows[0].ToString();
                    myDataTable.Rows.Add(row);
                    foreach (DataColumn dc in RightTable.Columns)
                    {
                        if (dc.Ordinal != 0)
                            myDataTable.Rows[count][dc.ColumnName.ToString().Trim()] =
                    rightTableDataRows[dc.ColumnName.ToString().Trim()].ToString();
                    }
                }
            }

            return myDataTable;
        }

        #endregion
    }
}


    #endregion 